{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#  Compare Model Zoo Benchmark performance between Intel optimized and stock PyTorch\n",
    "\n",
    "This jupyter notebook will help you evaluate performance benefits from Intel-optimized PyTorch which uses Intel-PyTorch-Extension package to boost the performance.\n",
    "The notebook will show users a bar chart like below for performance comparison among Stock and Intel PyTorch.\n",
    "\n",
    "Please change kernels between intel-torch and stock-torch. Run last cell only when you're done running both kernels."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"images\\perf_compare.png\"  />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Get Platform Information "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ignore all warning messages\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/tmp/models/docs/notebooks/perf_analysis/pytorch/profiling/../../../../../benchmarks/common\n",
      "==================== CPU Info ====================\n",
      "Physical cores per socket: 28\n",
      "Total physical cores: 56\n",
      "Max Frequency: 4000.0\n",
      "Min Frequency: 1000.0\n",
      "Socket Number: 2\n",
      "==================== Memory Information ====================\n",
      "Total:  251 GB\n"
     ]
    }
   ],
   "source": [
    "from profiling.profile_utils import PlatformUtils\n",
    "plat_utils = PlatformUtils()\n",
    "plat_utils.dump_platform_info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='section_1'></a>\n",
    "# Section 1: Run the benchmark on the selected Jupyter Kernels"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 1: Check PyTorch version and IPEX enablement"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "We are using PyTorch version 1.7.0a0+e85d494\n",
      "IPEX version: 1.2.0\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "print (\"We are using PyTorch version\", torch.__version__)\n",
    "try:\n",
    "    import intel_pytorch_extension as ipex\n",
    "    print(\"IPEX version: {}\".format(ipex.__version__))\n",
    "    has_ipex = True\n",
    "except ImportError:\n",
    "    print(\"WARNING: IPEX not available\")\n",
    "    has_ipex = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2: Configure parameters for pytorch's launch utility according to the selected Topology"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 2.1: List out the supported topologies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Supported topologies: \n",
      " 0: resnet50 infer fp32 \n",
      " 1: vgg16 infer fp32 \n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "from profiling.profile_utils import ConfigFile\n",
    "\n",
    "accuracy_only=False\n",
    "\n",
    "config = ConfigFile()\n",
    "sections = config.read_supported_section(accuracy_only=accuracy_only)\n",
    "print(\"Supported topologies: \")\n",
    "index =0 \n",
    "for section in sections:\n",
    "    print(\" %d: %s \" %(index, section))\n",
    "    index+=1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 2.2: Pick a topology. \n",
    "#### ACTION : Please select one supported topology and change topo_index accordingly"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# User picks a topology, Batch Size, and number of required threads\n",
    "## USER INPUT\n",
    "topo_index=0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### List out the selected topology name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "resnet50 infer fp32\n"
     ]
    }
   ],
   "source": [
    "if topo_index >= len(sections):\n",
    "    print(\"ERROR! please input a topo_index within range\")\n",
    "else:\n",
    "    topology_name=sections[topo_index]\n",
    "    print(topology_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/tmp/models/docs/notebooks/perf_analysis/pytorch/../../../../\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "# Users should change ModelZooRoot path according to their environment\n",
    "## USER INPUT\n",
    "current_path = os.getcwd()\n",
    "os.environ['ModelZooRoot'] = current_path + \"/../../../../\"\n",
    "print(os.environ['ModelZooRoot'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Check those mandatory python scripts after users assign ModelZooRoot and ProfileUtilsRoot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "sys.path.append(os.environ['ModelZooRoot']+os.sep+'benchmarks/common/')\n",
    "from platform_util import CPUInfo \n",
    "cpu_info = CPUInfo()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU count per socket: 28  \n",
      "Socket count: 2\n"
     ]
    }
   ],
   "source": [
    "import psutil\n",
    "import subprocess\n",
    "import os\n",
    "cpu_count = cpu_info.cores_per_socket\n",
    "cpu_socket_count =  cpu_info.sockets\n",
    "print(\"CPU count per socket:\" ,  cpu_count ,\" \\nSocket count:\",cpu_socket_count)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### ACTION: Users can change the value of thread_number and batch_size to see different performance\n",
    "1. thread_number: the value will apply to num_cores parameters in launch_benchmark.py  \n",
    "2. utilized_socket_number:  the value will apply to the socket-id parameter in launch_benchmark.py \n",
    "3. num_inter_threads: the value will  apply to the num-inter-threads parameter in launch_benchmark.py \n",
    "4. num_intra_threads: the value will  apply to the num-intra-threads parameter in launch_benchmark.py \n",
    "5. batch_size: the value will apply to the batch_size parameter in launch_benchmark.py \n",
    "6. log_folder: the folder where the logs are stored."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "## USER INPUT\n",
    "thread_number=1 \n",
    "utilized_socket_number=2 #cpu_socket_count\n",
    "num_inter_threads = utilized_socket_number\n",
    "num_intra_threads = thread_number\n",
    "batch_size=32\n",
    "log_folder=os.getcwd() + os.sep + \"logs\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "current_path = os.getcwd()\n",
    "log_dir = os.path.join(current_path, \"logs\")\n",
    "log_filename = topology_name.replace(' ', '_') + '.log'\n",
    "log_path = os.path.join(log_dir, log_filename)\n",
    "from torch.distributed import launch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 2.3: Prepare pre-trained model and model parameters for running the benchmark\n",
    "1. Get related parameters according to selected topology\n",
    "2. Get pretrained model if needed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['torch.distributed.launch', '--nnodes=2', '--node_rank=2', '--nproc_per_node=1', '--use_env', '/tmp/models/docs/notebooks/perf_analysis/pytorch/../../../..//models/image_recognition/pytorch/common/main.py', '--batch-size', '32', '--arch', 'resnet50', '--dummy', '--evaluate', '--pretrained', '--ipex', '--precision', 'fp32', '--jit', '--warmup-iterations', '30', '--log-path=/tmp/models/docs/notebooks/perf_analysis/pytorch/logs/resnet50_infer_fp32.log']\n"
     ]
    }
   ],
   "source": [
    "config = ConfigFile()\n",
    "configvals = []\n",
    "# Get common parameters according to users' inputs\n",
    "params = [\"torch.distributed.launch\"]\n",
    "params.extend(config.get_launch_parameters(configvals, thread_number=thread_number,\n",
    "                                socket_number=utilized_socket_number, num_inter_threads=num_inter_threads,\n",
    "                                num_intra_threads=num_intra_threads,\n",
    "                                accuracy_only=False))\n",
    "main_script = os.environ['ModelZooRoot']+os.sep+'models/image_recognition/pytorch/common/main.py'\n",
    "params += [main_script]\n",
    "params.extend(config.get_main_parameters(topology_name = topology_name.split(\" \")[0], mode = \"infer\",\n",
    "                                         batch_size=batch_size, has_ipex = has_ipex,\n",
    "                                         precision=\"fp32\", warmup_iter=30, log_path=log_path))\n",
    "\n",
    "    \n",
    "sys.argv=params\n",
    "print(sys.argv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 2.4: Create a CSV file to log the performance numbers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "file exists\n"
     ]
    }
   ],
   "source": [
    "from profiling.profile_utils import PerfPresenter\n",
    "job_type = topology_name.split(' ')[1]#'inference'\n",
    "csv_fname=job_type+'_'+topology_name.replace(' ', '_')+'.csv'\n",
    "perfp=PerfPresenter()\n",
    "perfp.create_csv_logfile(job_type, csv_fname)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3:  Run the benchmark "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "launch.main()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4: Parse output for performance number"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Found the file path of the related runtime log."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/tmp/models/docs/notebooks/perf_analysis/pytorch/logs/resnet50_infer_fp32.log\n"
     ]
    }
   ],
   "source": [
    "# identify the path of the latest log file\n",
    "configvals=config.read_config(topology_name)\n",
    "used_logpath = log_path\n",
    "print(used_logpath)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Parse the logfile for performance number."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "get throughput\n",
      "inference performance 214.138 fps\n",
      "\n",
      "214.138\n",
      "214.138\n"
     ]
    }
   ],
   "source": [
    "print(\"get throughput\")\n",
    "val = config.throughput_keyword\n",
    "index = int(config.throughput_index)\n",
    "line = perfp.read_throughput(used_logpath, keyword=val, index=index)\n",
    "if line!=None:\n",
    "    throughput=line\n",
    "    print(throughput)\n",
    "    # log the perf number\n",
    "    perfp.log_infer_perfcsv(0, throughput, 0, csv_fname, ipex_enabled = has_ipex)\n",
    "else:\n",
    "    print(\"ERROR! can't find correct performance number from log. please check log for runtime issues\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Optional : print out the log file for runtime issues"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=> using pre-trained model 'resnet50'\n",
      "using CPU, this will be slow\n",
      "using ipex model to do inference\n",
      "running jit fusion path\n",
      "using dummy input data to run\n",
      "Test: [ 0/50]\tTime  0.000 ( 0.000)\tLoss 9.8397e+00 (9.8397e+00)\tAcc@1   0.00 (  0.00)\tAcc@5   0.00 (  0.00)\n",
      "Test: [10/50]\tTime  0.000 ( 0.000)\tLoss 9.8397e+00 (9.8397e+00)\tAcc@1   0.00 (  0.00)\tAcc@5   0.00 (  0.00)\n",
      "Test: [20/50]\tTime  0.000 ( 0.000)\tLoss 9.8397e+00 (9.8397e+00)\tAcc@1   0.00 (  0.00)\tAcc@5   0.00 (  0.00)\n",
      "Test: [30/50]\tTime  0.174 ( 0.174)\tLoss 9.8397e+00 (9.8397e+00)\tAcc@1   0.00 (  0.00)\tAcc@5   0.00 (  0.00)\n",
      "Test: [40/50]\tTime  0.141 ( 0.151)\tLoss 9.8397e+00 (9.8397e+00)\tAcc@1   0.00 (  0.00)\tAcc@5   0.00 (  0.00)\n",
      "inference latency 4.670 ms\n",
      "inference performance 214.138 fps\n",
      " * Acc@1 0.000 Acc@5 0.000\n",
      "DoneClosing\n"
     ]
    }
   ],
   "source": [
    "logfile = open(used_logpath)\n",
    "logout = logfile.read()\n",
    "print(logout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5: Draw the performance comparison diagram\n",
    ">NOTE: Please go over Section 1 on different Jupyter kernel before comparison\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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0axZs9zytt3ly5dHX3/9dbTddtu54Zw5c6Kf/exn6+yHrWPrb7LJJm6Z1q1bR5tttpkr28own376aVRRURF16NAh+vbbb906P/nJTyrXt3Hb99WrV7t13n333cp5tf0uixYtcuv/+Mc/jj788ENXrq1v2/nyyy8ro23btTvJ/+STT1zYZ8nva+vZ97NyMt83ybY/c+ZMt1/rrVd89Ypp06Yt13e3rrHWFlK3HXvuuacGABrTypUr7Q/FWCfnape59tpr4zPPPNMtM2/evHinnXaKdZJda5kvvvgi3mOPPeKXX37ZTSsxVW7zgw8+iJUk3LiSYayT9TplLFmyJN51110rp0eNGhUPGDBgneVsfu/evatcxsZtXlK7du1iJbQ6fZdddtnF7V9mP206aeTIkfHZZ5+91rxVq1bFPXr0iJUA1/m+5513XvzYY4/F++yzTzxlij2jvbZhw4bFJ5xwwjrzi4VS0VQbZEfxpWIAdaKTdFReXh6deuqpkU7K0emnnx7pBL3WMoMGDXK1k2233Tb6+c9/Ht16662Vf9lbbaBz586utnPQQQdFv/jF949V7b777tGjj7rO2qNx48ZFCxcuXKvGZmXpBB09/7y9GSWKFi9e7GolGTZu8zJuv/32SMkk+sMf/hDddtttletYDaS6dapSm+/y0UcfRdtsY90WRm64bJk9DlezP/7xj9EFF1wQ/ehH1k/wD1577TV3LA477LBq1x0zZkzUt2+mV6zSsV7KvQgkr59+VotuaAA0MLucNH369Ei1CnfytMtNf/mLPW/9gyeffNKduFV7iF5//XV3kv/sM3vONnKXxGyeXQZ79dVX3aUpc9ddd7mkoislkWoT0YYbblh5gleNypV18803R6opuG19/4f12vwtKEc1lGju3LnR9ddfH11zzffPAudapyq1+S6Fsm3YJbwjjzxyrfl2CfH888+PbrrppmrXXapLkG+++Wb0q19Zv7ulJbUEpV+U2YrOFprc03f0aE/pAwiY1TosMrWFY445xiWsJF3Cio466ih38t95552jHXbYwd2jSdp8882jfffdN5o4caKb3m233aJJkybZ/QZXG7Daj9loo42iLbf8vncjS1423+4T2T5YYsiwcavlZDv++OOjhx/+/pVctk6yZlbdOnX9LltvvbVLHMaGVsOqyUsvveS+t91j79mzp/t+tj1L1Jb0bNw+0yXE6PDDD4+mTv3hVWFjx451iW2DDewNLqWlod6oa93PzFWySvZynBe7aWm/ZF99lewAGfWtefPm7j93Kf4nwNrsxr9dJps9e3ake0DRP//5z+inP61sJOfYzX+bv/fee7vLXbbsjjvu6Bor2O+QndCtIcDTTz8dXXzxxW4duwxmJ3KrNViNZ+DAgd93b651WrVq5Wordnnxvffec9uyedagwk7aliz//ve/R+ecc45bx5axRhFmwoQJleNWy7j00ktdQwRjCfG66+ztKdWrzXexJHLPPfdEgwcPdsMjjqi5+0KrjVqYBQsWuMt5kydPdtPWYCTDEtWNN94Yde3qGvI5o0ePzvkdilZVN6bqO+QuxaBqPhugsD8XpuoXZZ2bZ3bT0m5o1nTDFnVjx9aOsR1rwOhyW2yNlnRPJtbJN/7444/joUOHujC6rxPrnkys+0ruhv+9997r5s+YMSPW5TK3ns2/6qqrKg/oLbfcEiuRuNCJvvL/9AMPPBArAcZqoeYaIug+VeU61mDAtqOE4RodZNY599xz3TqdOnWKdVKPVQupXGfEiBGuoYOFLitWzte9pVitBmMlwliXFePTTjut1t9FSSXef//9Y9W43HDFCnvLyg+NMLbYYotYl0ZdedYoIqm6RiEmu5HEfC2rGuA6jTaKjZ3/bZAdqTczt56ZfSec9hOx3pSrpb8a4mTV1tjNS7s0kOs6MurGfg/sskameS4ANBSd36fpHPRDtdFriFZ8hyim50pONSE5pY9jDCA0DZGg+vou/gEACKORhP4qtwb/BynOqK9tth88ob425Sz4y6G1Wk/X06MBAwas80xDPoYMGeKeRr/wwgur/PzPf/6ze07EWPNSezbD9O/fP9K191rtr5X3+eef12pdACi6BKXLeta0vCjfjmkJ6qSTTqpVgsrlsssuc5FJLPYMRb7PryS7owGApoyzWQ72BP1vfvMb19Tdniq3p8GtKao91Lfffvu5vsqeeeYZ1xT02muvdY0NDj30UPfwoLHnJqzZq61ry1pz1qS//e1v0UMPPeRi442rf5GoNbO3ZqrWiMSSkD3QaOXffffdrpmtfW77ak/qW1NcW87uK1155ZXR0Ucf7bZhSe/xxx935TzyyCPuWQ4EYkjyLexAEzFkZaqbJ0HlYAnGHvSzJGBWrlzpOqu0BGGJyZKOJSt7PsIexFPz0ujggw92Dw726NEj+u1vfxs999xz7uE/NdVda9t//etf3XMatqw9rFgTewI/c8nPWttZGfawX+YhwDfeeMM9N2L7Yftny5nM8yCWvH75y1+6y4fWNYwlxssvv7zAXxcAaDj0xZeD3f/JPKBnfYTZyT/blClT3AN21n+Z1W5OPPFEl5TsAcNevXq55GQsgWTce++90RNPPBE9+OCDOZOTeeGFF6KTTz7ZjVuz+3bt2lUmKOsjLLNt21frAibDEqaxbmUyfX3Z0/r2sCAAhIwElcMuu+ziakaWqC655JLo6quvXmeZ6p4lcw+aVfP8lnWcaUki2ZVLTWp6Xi3ZNX91ZdoT8Zn59sS+3a8CgJCRoHKwy3fWEMIaRFiru0yfZNYFi/WjZawblmeffdZ1WWL3mux+lPXK3L17dzd//vz5brnkJT7ruXnYsGGuyxQrIxerid1///1u3GpO1rmmdUOTzS792aXDjMwlPgBoaprcPajaNguvLbuXc9FFF7nu960WMnToUDffmpgfcsghridmuxdlfWVZowWrwfTp06eyb67hw4e7jiit/zHrh+ypp56q3LZ1Gmn9blmjCptv97Oqc9ZZZ7m+y6wmZ5cRrXFEVZcG7b6SXeKzGprVlKyRhJUPAE1NUG/Ura6rI7rfaRgc60ZEKz6UcCu+skbs6ggAgIKRoAAAQSJBAQCCRIICAASJBAUACBIJCgAQpCb3HFS9N8fNo5nkXnvtFb344ov18voN6xLJnn3q2vWHFpVHHnmke5jXXodRUVFR2TXSHXfc4cou1OTJk10Z1jEsADRVTS9BNYJcyamur98YP358rRILr9cAUMy4xJcHeydTJoFYDeiYY45xHbZap7D2oPNtt91W+foNC2O9lFtXR126dImOPfbYgl8W+P7770cHHHBA1LFjRze0ro1Mv379ot///veuHOvAds6cOdGBBx4YderUyZU1d+5ct5yVl72fANCUkKAK9Nprr7na0ttvvx3Nmzcv+te//uXecmuv5LAujyysT75rrrnG9SxufffZ5Tx7PUchBg0aFJ1yyinuNRqWYJJv0rW++GzbN910k/vMujaaMWOGq+lZ10vV7ScANCUkqAJ169YtatOmjeubr3PnzlW+tsJes2GJwd4HZcvcc889rkZUCHvH0wknnODG7TUb9rqNDKuRWT971lnt4sWL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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib\n",
    "%matplotlib inline\n",
    "from profiling.profile_utils import PerfPresenter\n",
    "\n",
    "perfp=PerfPresenter(True)\n",
    "# inference  throughput\n",
    "perfp.draw_perf_diag_from_csv(csv_fname,'throughput','throughput (image/sec)', topology_name)\n",
    "perfp.draw_perf_ratio_diag_from_csv(csv_fname,'throughput','speedup', topology_name)\n",
    "if accuracy_only == True:\n",
    "    perfp.draw_perf_diag_from_csv(csv_fname,'accuracy','accuracy', topology_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "intel-torch",
   "language": "python",
   "name": "intel-torch"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
